package and.geo.matrix;



import and.awt.geom.AffineTransform;
import and.awt.geom.NoninvertibleTransformException;
import and.awt.geom.Rectangle;

public final class RendererUtilities {

	private RendererUtilities() {

	}
	public static com.vividsolutions.jts.geom.Envelope createMapEnvelope(Rectangle paintArea,
			AffineTransform worldToScreen) throws NoninvertibleTransformException {
		  //
        // (X1,Y1) (X2,Y1)
        //
        // (X1,Y2) (X2,Y2)
        double[] pts = new double[8];
        pts[0] = paintArea.getMinX();
        pts[1] = paintArea.getMinY();
        pts[2] = paintArea.getMaxX();
        pts[3] = paintArea.getMinY();
        pts[4] = paintArea.getMaxX();
        pts[5] = paintArea.getMaxY();
        pts[6] = paintArea.getMinX();
        pts[7] = paintArea.getMaxY();
        worldToScreen.inverseTransform(pts, 0, pts, 0, 4);
        double xMin = Double.POSITIVE_INFINITY;
        double yMin = Double.POSITIVE_INFINITY;
        double xMax = Double.NEGATIVE_INFINITY;
        double yMax = Double.NEGATIVE_INFINITY;
        for (int i = 0; i < 4; i++) {
            xMin = Math.min(xMin, pts[2 * i]);
            yMin = Math.min(yMin, pts[2 * i + 1]);
            xMax = Math.max(xMax, pts[2 * i]);
            yMax = Math.max(yMax, pts[2 * i + 1]);
        }
        return new com.vividsolutions.jts.geom.Envelope(xMin, xMax, yMin, yMax);
	}
	public static AffineTransform worldToScreenTransform(com.vividsolutions.jts.geom.Envelope mapExtent,
			Rectangle paintArea) {
		double scaleX = paintArea.getWidth() / mapExtent.getWidth();
		double scaleY = paintArea.getHeight() / mapExtent.getHeight();

		double tx = -mapExtent.getMinX() * scaleX;
		double ty = (mapExtent.getMinY() * scaleY) + paintArea.getHeight();

		AffineTransform at = new AffineTransform(scaleX, 0.0d, 0.0d, -scaleY,
				tx, ty);
		AffineTransform originTranslation = AffineTransform
				.getTranslateInstance(paintArea.x, paintArea.y);
		originTranslation.concatenate(at);

		return originTranslation != null ? originTranslation : at;
	}

	/**
	 * Calculates transforms suitable for aspect ratio matching. The world
	 * bounds will be centred in the screen area.
	 */
	public static AffineTransform calculateCenteringTransforms(Envelope bounds,
			Rectangle screenArea) {
		AffineTransform worldToScreen;
		double xscale = screenArea.getWidth() / bounds.getWidth();
		double yscale = screenArea.getHeight() / bounds.getHeight();

		double scale = Math.min(xscale, yscale);

		double xoff = bounds.getMedian(0) * scale - screenArea.getCenterX();
		double yoff = bounds.getMedian(1) * scale + screenArea.getCenterY();

		worldToScreen = new AffineTransform(scale, 0, 0, -scale, -xoff, yoff);
		// screenToWorld = worldToScreen.createInverse();
		return worldToScreen;
	}

	/**
	 * Calculates transforms suitable for no aspect ratio matching.
	 * 
	 * @param requestedBounds
	 *            requested display area in world coordinates
	 */
	public static AffineTransform calculateSimpleTransforms(
			Envelope requestedBounds, Rectangle screenArea) {
		AffineTransform worldToScreen;
		double xscale = screenArea.getWidth() / requestedBounds.getWidth();
		double yscale = screenArea.getHeight() / requestedBounds.getHeight();

		worldToScreen = new AffineTransform(xscale, 0, 0, -yscale, -xscale
				* requestedBounds.getMinX(), yscale * requestedBounds.getMaxY());
		return worldToScreen;
	}
}
